#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>
#include "Common.hpp"
#include "Log.hpp"

const std::string Sep = "\r\n"; //一行分隔符
const std::string LineSep = " "; //第一行行内分隔符
const std::string HeaderLineSep = ": "; //属性行的分隔符

using namespace LogModule;

class HttpRequest
{
public:
    HttpRequest(){}
    ~HttpRequest(){}

    //http请求
    // GET /favicon.ico HTTP/1.1\r\n
    // Host: 8.137.19.140:8080
    // Connection: keep-alive
    // User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0
    // Accept: image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8
    // Referer: http://8.137.19.140:8080/?msg=i_have_sent_a_message_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_he_
    // Accept-Encoding: gzip, deflate
    // Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
    // dnt: 1
    // sec-gpc: 1

    //反序列化, 查看请求中的详细信息
    void Deserialize(std::string &request_str)
    {
        if(ParseOneLine(request_str, &_req_line, Sep)) //提取第一行的信息, 公共方法
        {
            //提取第一行的详细字段
            ParseReqLine(_req_line, LineSep);//私有方法
            ParseHeader(request_str); //请求属性参数
            _body = request_str;
        }
        //Print();
    }

    //发送请求的文件内容
    std::string GetContent(const std::string path)
    {
        //二进制读取任意的文件
        std::string content;
        std::ifstream in(path, std::ios::binary); //以二进制的方式打开
        if(!in.is_open())
            return std::string();
        in.seekg(0, in.end); //修改读取位置
        int filesize = in.tellg(); //获取读取位置, 获取字节数
        in.seekg(0, in.beg); //修改到最开始位置

        content.resize(filesize); //开辟大小
        in.read((char*)content.c_str(), filesize);
        in.close();
        LOG(LogLevel::DEBUG) << "content length: " << content.size();
        return content;
    }

    bool ParseHeader(std::string &request_str)
    {
        std::string line;
        while(true)
        {
            bool r = ParseOneLine(request_str, &line, Sep); //一行一行的读取
            if(r && !line.empty())
            {
                //说明没有读取到空行, 并且读取成功了
                _req_header.push_back(line); //插入到属性行
            }
            else if(r && line.empty())
            {
                //说明读取成功了, 读到了空行, 就不需要读取了
                _blank_line = Sep;
                break;
            }
            else
            {
                //读取失败
                return false;
            }
        }
        ParseHeaderKv(); //我们想获取到详细的键值, 把属性行进行拆解
        return true;
    }

    bool ParseHeaderKv()
    {
        std::string key, value;
        for(auto &header : _req_header)
        {
            //把属性行进行拆分, 公共方法
            if(SplitString(header, HeaderLineSep, &key, &value))
            {
                _headerkv.insert(std::make_pair(key, value));
            }
        }
        return true;
    }

    void Print()
    {
        std::cout << "_method: " << _method << std::endl;
        std::cout << "_uri: " << _uri << std::endl;
        std::cout << "_version" << _version << std::endl;

        for(auto &kv : _headerkv)
        {
            std::cout << kv.first << " # " << kv.second << std::endl;
        }
        std::cout << "_blank_line: " << _blank_line << std::endl;
        std::cout << "_body: " << _body << std::endl;
    }

    std::string Uri()
    {
        //获取uri, 请求的文件
        return _uri;
    }

    void SetUri(const std::string newuri)
    {
        _uri = newuri; // 设置新的uri
    }

    std::string Suffix()
    {
        auto pos = _uri.rfind(".");
        if(pos == std::string::npos)
            return std::string(".html");
        else
            return _uri.substr(pos);
    }

private:

    void ParseReqLine(std::string &_req_line, const std::string sep)
    {
        (void)sep;
        std::stringstream ss(_req_line);
        ss >> _method >> _uri >> _version;
    }

    std::string _req_line; //请求头, 第一行
    std::vector<std::string> _req_header; //请求属性,一行一行的
    std::string _blank_line; //空行
    std::string _body; //请求正文

    //在反序列化的过程中, 细化我们解析出来的字段
    std::string _method; //第一行第一个字段, 请求的方法
    std::string _uri; //第一行第二个字段,请求的文件
    std::string _version; //第一行第三个字段,请求的版本

    std::unordered_map<std::string, std::string> _headerkv; //请求属性参数中的键值
};


const std::string http_version = "HTTP/1.0";
const std::string defaulthomepage = "wwwroot";
const std::string firstpage = "index.html";
const std::string page404 = "wwwroot/404.html";

//对于任何http请求, 都要有应答
class HttpResponse
{
public:
    HttpResponse()
    : _version(http_version)
    , _blank_line(Sep)
    {}
    ~HttpResponse(){}

    //构建返回字段
    void Build(HttpRequest &req)
    {
        std::string uri = defaulthomepage + req.Uri();
        if(uri.back() == '/')
        {
            uri += firstpage;
        }
        LOG(LogLevel::DEBUG) << "--------客户端在请求: " << req.Uri();
        req.Print();
        LOG(LogLevel::DEBUG) << "---------------------";

        _content = req.GetContent(uri); //1

        if(_content.empty())
        {
            _status_code = 404; //2
            _content = req.GetContent(page404);
        }
        else
        {
            _status_code = 200;
        }

        _status_desc = Code2Desc(_status_code);//和状态码是强相关的 //3

        if(!_content.empty())
        {
            SetHeader("Content-Length", std::to_string(_content.size()));
        }

        std::string mime_type = Suffix2Desc(req.Suffix()); //文件类型 
        SetHeader("Content-Type", mime_type); //设置文件类型参数

        _body = _content;

    }

    //手动设置状态码
    void SetCode(int code)
    {
        _status_code = code;
        _status_desc = Code2Desc(_status_code);
    }    

    //手动设置body
    void SetBody(const std::string &body)
    {
        _body = body;
    }

    void SetHeader(const std::string &k, const std::string &v)
    {
        _header_kv[k] = v;
    }
    
    //把响应序列化
    void Serialize(std::string *resp_str)
    {
        //设置请求属性
        for(auto &header : _header_kv)
        {
            _resp_header.push_back(header.first + HeaderLineSep + header.second);
        }

        //设置请求头
        _rep_line = _version + LineSep + std::to_string(_status_code) + LineSep + _status_desc + Sep;

        //序列化
        *resp_str = _rep_line;
        for(auto &line : _resp_header)
        {
            *resp_str += (line + Sep);
        }
        *resp_str += _blank_line;
        *resp_str += _body;
    }

private:
    std::string Code2Desc(int code)
    {
        switch(code)
        {
            case 200:
                return "OK";
            case 404:
                return "Not Found";
            default:
                return std::string();
        }
    }

    std::string Suffix2Desc(const std::string &suffix)
    {
        if(suffix == ".html")
            return "text/html";
        else if(suffix == ".jpg")
            return "applocation/x-jpg";
        else
            return "text/html";
    }

    //最终要这4部分,构建应答
    std::string _rep_line; //响应头
    std::vector<std::string> _resp_header; //响应的属性字段
    std::string _blank_line; //空行
    std::string _body; //响应正文

    //必备的要素
    std::string _version; //http版本
    int _status_code; //状态码
    std::string _status_desc; //状态码描述
    std::string _content; //正文信息
    std::unordered_map<std::string, std::string> _header_kv; //属性字段
};